﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CLUBsInterpreter.AST;
using CLUBsInterpreter.ObjectTypes;
using System.Drawing;

namespace CLUBsInterpreter
{
	/**
	 * <summary>
	 * Describes a standard environment for the CLUBs interpreter.
	 * This includes built-in actions, special variables like CurrentPlayer, etc.
	 * </summary>
	 **/
	class StandardEnvironment
	{
		public static StandardEnvironment Instance
		{
			private set;
			get;
		}

		/**
		 * <summary>
		 * Global variables accessible from CLUBs programs
		 * </summary>
		 **/
		public Dictionary<string, CLUBsObject> GlobalVariables = new Dictionary<string, CLUBsObject>();

		public BlockNode CurrentBlock;

		public bool ExecutionReturnTriggered = false;

		public bool SelectingCell = false;
		public CLUBsCell SelectedCell = null;

		// ############# STACKS #############
		public Stack<BlockNode> BlockReturnStack = new Stack<BlockNode>();

		/**
		 * <summary>
		 * Return register stack. The topmost object is to be set with any return value from an action.
		 * </summary>
		 **/
		public Stack<CLUBsObject> ReturnStack = new Stack<CLUBsObject>();
		/**
		 * <summary>
		 * Parameter bank stack. The topmost dictionary is to be filled with parameter objects for an action.
		 * </summary>
		 **/
		public Stack<Dictionary<string, CLUBsObject>> ParameterBankStack = new Stack<Dictionary<string, CLUBsObject>>();
		// ##################################

		/**
		 * <summary>
		 * Default constructor initializes the standard environment.
		 * </summary>
		 **/
		public StandardEnvironment()
		{
			// Set the static instance reference
			StandardEnvironment.Instance = this;

			// Boolean values
			GlobalVariables["true"] = new CLUBsBoolean(true);
			GlobalVariables["false"] = new CLUBsBoolean(false);
			// Null value
			GlobalVariables["null"] = new CLUBsNull();

			// CurrentPlayer variable
			GlobalVariables["CurrentPlayer"] = new CLUBsPlayer();

			// CurrentRound variable
			GlobalVariables["CurrentRound"] = new CLUBsRound();

			// CurrentBoard variable
			GlobalVariables["CurrentBoard"] = new CLUBsBoard();
			GlobalVariables["CurrentBoard"].LocalVariables.Declare("NullBoard", (CLUBsBoolean)true);

			// GameHasEnded bool
			GlobalVariables["GameHasEnded"] = new CLUBsBoolean(false);

			// ACTION DEFINITIONS
			Dictionary<string, IdentifierType> pTypes;
			CLUBsAction action;

			#region Win
			// Win action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add winPlayer parameter
			pTypes["winPlayer"] = IdentifierType.Player;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_Win;
			// Add the CLUBsAction to the global variables
			GlobalVariables["Win"] = action;
			#endregion

			#region Lose
			// Lose action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add losePlayer parameter
			pTypes["losePlayer"] = IdentifierType.Player;
			// Instantiate CLUBsAction for action
			action = new CLUBsAction(paramTypes: pTypes);
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_Lose;
			// Add the CLUBsAction to the global variables
			GlobalVariables["Lose"] = action;
			#endregion

			#region EndGame
			// EndGame action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Instantiate CLUBsAction for action
			action = new CLUBsAction(paramTypes: pTypes);
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_EndGame;
			// Add the CLUBsAction to the global variables
			GlobalVariables["EndGame"] = action;
			#endregion

			#region Print
			// Print action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["printString"] = IdentifierType.Unset;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			action.Name = "Print";
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_Print;
			// Add the CLUBsAction to the global variables
			GlobalVariables["Print"] = action;
			#endregion

			#region UseRound
			// UseRound action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["round"] = IdentifierType.Round;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_UseRound;
			// Add the CLUBsAction to the global variables
			GlobalVariables["UseRound"] = action;
			#endregion

			#region DoTurn
			// DoTurn action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["turn"] = IdentifierType.Turn;
			pTypes["player"] = IdentifierType.Player;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_DoTurn;
			// Add the CLUBsAction to the global variables
			GlobalVariables["DoTurn"] = action;
			#endregion

			#region MakeRect
			// MakeRect action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["width"] = IdentifierType.Integer;
			pTypes["height"] = IdentifierType.Integer;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_MakeRect;
			// Add the CLUBsAction to the global variables
			GlobalVariables["MakeRect"] = action;
			#endregion

			#region SelectCell
			// SelectCell action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["paramName"] = IdentifierType.String;
			pTypes["paramValue"] = IdentifierType.Boolean;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Set return type
			action.ReturnType = IdentifierType.Cell;
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_SelectCell;
			// Add the CLUBsAction to the global variables
			GlobalVariables["SelectCell"] = action;
			#endregion

			#region GetCellAt
			// SelectCell action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["x"] = IdentifierType.Integer;
			pTypes["y"] = IdentifierType.Integer;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Set return type
			action.ReturnType = IdentifierType.Cell;
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_GetCellAt;
			// Add the CLUBsAction to the global variables
			GlobalVariables["GetCellAt"] = action;
			#endregion

			#region GetFirstPiece
			// GetFirstPiece action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["cellIn"] = IdentifierType.Cell;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Set return type
			action.ReturnType = IdentifierType.Piece;
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_GetFirstPiece;
			// Add the CLUBsAction to the global variables
			GlobalVariables["GetFirstPiece"] = action;
			#endregion

			#region PlacePiece
			// PlacePiece action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["piece"] = IdentifierType.Piece;
			pTypes["cell"] = IdentifierType.Cell;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Set return type
			action.ReturnType = IdentifierType.Boolean;
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_PlacePiece;
			// Add the CLUBsAction to the global variables
			GlobalVariables["PlacePiece"] = action;
			#endregion

			#region ClearCell
			// ClearCell action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["cell"] = IdentifierType.Cell;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_ClearCell;
			// Add the CLUBsAction to the global variables
			GlobalVariables["ClearCell"] = action;
			#endregion

			#region MoveAllPieces
			// ClearCell action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add sourceCell parameter
			pTypes["sourceCell"] = IdentifierType.Cell;
			// Add targetCell parameter
			pTypes["targetCell"] = IdentifierType.Cell;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Set return type
			action.ReturnType = IdentifierType.Boolean;
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_MoveAllPieces;
			// Add the CLUBsAction to the global variables
			GlobalVariables["MoveAllPieces"] = action;
			#endregion

			#region ThreeInARow
			/*// ThreeInARow action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["board"] = IdentifierType.Board;
			//pTypes["piece"] = IdentifierType.Piece;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Set return type
			action.ReturnType = IdentifierType.Boolean;
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_ThreeInARow;
			// Add the CLUBsAction to the global variables
			GlobalVariables["ThreeInARow"] = action;*/
			#endregion

			#region FourInARow
			// FourInARow action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add printString parameter
			pTypes["board"] = IdentifierType.Board;
			//pTypes["piece"] = IdentifierType.Piece;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Set return type
			action.ReturnType = IdentifierType.Boolean;
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_FourInARow;
			// Add the CLUBsAction to the global variables
			GlobalVariables["FourInARow"] = action;
			#endregion

			#region MathAbs
			// MathAbs action
			// Instantiate parameter type dictionary
			pTypes = new Dictionary<string, IdentifierType>();
			// Add n parameter
			pTypes["n"] = IdentifierType.Integer;
			// Instantiate CLUBsAction for the action
			action = new CLUBsAction(paramTypes: pTypes);
			// Set return type
			action.ReturnType = IdentifierType.Integer;
			// Add the proper C# code to its translated method
			action.TranslatedMethod += Action_MathAbs;
			// Add the CLUBsAction to the global variables
			GlobalVariables["MathAbs"] = action;
			#endregion
		}

		/**
		 * <summary>
		 * Calls an action, handling parameters and return value on the stacks.
		 * </summary>
		 * <param name="action"> The CLUBsAction to call. </param>
		 * <param name="args"> Array of CLUBsObject parameters. </param>
		 * <returns> The CLUBsObject returned by the CLUBsAction. </returns>
		 **/
		public CLUBsObject CallAction(CLUBsAction action, params CLUBsObject[] args)
		{
			// Push null object into the return stack, to be replaced by the action
			ReturnStack.Push(null);
			// Push empty dictionary into parameter stack
			ParameterBankStack.Push(new Dictionary<string, CLUBsObject>());
			// Populate the parameter dictionary with the given parameters
			int i = 0;
			foreach (CLUBsObject obj in args)
			{
				ParameterBankStack.Peek().Add(action.ParameterTypes.ElementAt(i).Key, obj);
				action.LocalVariables.Declare(action.ParameterTypes.ElementAt(i).Key, obj);
				i++;
			}

			// Execute the action
			action.Execute();

			if (action.TranslatedMethod != Action_give)
			{
				ExecutionReturnTriggered = false;
			}

			// Pop the top parameter dictionary
			ParameterBankStack.Pop();
			// Return the return value, popping it off the return stack
			return ReturnStack.Pop();
		}

		public void Action_give()
		{
			ReturnStack.Pop();
			ReturnStack.Pop();
			ReturnStack.Push(ParameterBankStack.Peek()["retval"]);
			ReturnStack.Push(null);
			ExecutionReturnTriggered = true;
		}

		/**
		 * <summary>
		 * The native C# code for the built-in action Win.
		 * </summary>
		 **/
		private void Action_Win()
		{
			// Get the winning player from the parameters
			CLUBsPlayer winningPlayer = (CLUBsPlayer)ParameterBankStack.Peek()["winPlayer"];
			// TODO: Set player win status muligvis done
			winningPlayer.LocalVariables["HasWon"] = new CLUBsBoolean(true);
		}

		/**
		 * <summary>
		 * The native C# code for the built-in action lose.
		 * </summary>
		 **/
		private void Action_Lose()
		{
			//Get the losing player from the parameters
			CLUBsPlayer losingPlayer = (CLUBsPlayer)ParameterBankStack.Peek()["losePlayer"];
			//Sets the status of the losing player
			losingPlayer.LocalVariables["HasLost"] = new CLUBsBoolean(true);
		}

		private void Action_EndGame()
		{
			GlobalVariables["GameHasEnded"] = (CLUBsBoolean)true;
		}

		/**
		 * <summary>
		 * The native C# code for the built-in action Print.
		 * </summary>
		 **/
		private void Action_Print()
		{
			// Get the string from parameters
			CLUBsString str = ParameterBankStack.Peek()["printString"].ToString();
			// Write the string to console
			Console.WriteLine(str);
		}

		/**
		 * <summary>
		 * The native C# code for the built-in action DoTurn.
		 * </summary>
		 **/
		private void Action_DoTurn()
		{
			GlobalVariables["CurrentPlayer"] = ParameterBankStack.Peek()["player"];
			ParameterBankStack.Peek()["turn"].Execute();
		}

		private void Action_UseRound()
		{
			GlobalVariables["CurrentRound"] = ParameterBankStack.Peek()["round"];
		}

		private void Action_MakeRect()
		{
			CLUBsInteger width = (CLUBsInteger)ParameterBankStack.Peek()["width"];
			CLUBsInteger height = (CLUBsInteger)ParameterBankStack.Peek()["height"];

			CLUBsBoard board = (CLUBsBoard)((DefinitionNode)CurrentBlock).ObjectReference;
			board.Grid = new CLUBsCell[width, height];

			for (int x = 0; x < width; x++)
			{
				for (int y = 0; y < height; y++)
				{
					board.Grid[x, y] = new CLUBsCell();
					board.Grid[x, y].CopyValueFromObject(board.LocalVariables["CellType"]);
					board.Grid[x, y].LocalVariables["X"] = (CLUBsInteger)x;
					board.Grid[x, y].LocalVariables["Y"] = (CLUBsInteger)y;
				}
			}
		}

		private void Action_SelectCell()
		{
			CLUBsString varName = (CLUBsString)ParameterBankStack.Peek()["paramName"];
			CLUBsBoolean varVal = (CLUBsBoolean)ParameterBankStack.Peek()["paramValue"];

			CLUBsBoard board = (CLUBsBoard)GlobalVariables["CurrentBoard"];

			// Go through all cells in the board
			bool anyEligible = false;
			foreach (CLUBsCell cell in board.Grid)
			{
				// If they match the condition, make them eligible for selection
				try
				{
					if (cell.LocalVariables[varName] == varVal)
					{
						cell.Selectable = true;
						anyEligible = true;
					}
				}
				catch (KeyNotFoundException)
				{
					Console.WriteLine("Couldn't find "+varName);
					// KeyNotFoundException
				}
			}

			// If no cells were eligible, return CLUBsNull
			if (!anyEligible)
			{
				ReturnStack.Pop();
				ReturnStack.Push(new CLUBsNull());
				return;
			}

			// Await user input
			SelectingCell = true;
			Interpreter.GUI.Refresh();
			while (SelectingCell)
			{
				System.Threading.Thread.Sleep(10);
			}

			// Remove eligibilities
			foreach (CLUBsCell cell in board.Grid)
			{
				cell.Selectable = false;
			}

			// Ready user input return
			ReturnStack.Pop();
			ReturnStack.Push(SelectedCell);

			// Clean up SelectedCell
			SelectedCell = null;
		}

		private void Action_GetCellAt()
		{
			int x = (CLUBsInteger)ParameterBankStack.Peek()["x"];
			int y = (CLUBsInteger)ParameterBankStack.Peek()["y"];

			CLUBsBoard board = (CLUBsBoard)GlobalVariables["CurrentBoard"];

			ReturnStack.Pop();
			try
			{
				ReturnStack.Push(board.Grid[x, y]);
			}
			catch (IndexOutOfRangeException)
			{
				ReturnStack.Push(new CLUBsNull());
			}
		}

		private void Action_GetFirstPiece()
		{
			ReturnStack.Pop();

			if (ParameterBankStack.Peek()["cellIn"] is CLUBsNull)
			{
				ReturnStack.Push(new CLUBsNull());
				return;
			}

			CLUBsCell cell = (CLUBsCell)ParameterBankStack.Peek()["cellIn"];

			if (cell.Pieces.Count > 0)
			{
				ReturnStack.Push(cell.Pieces[0]);
			}
			else
			{
				ReturnStack.Push(new CLUBsNull());
			}
		}

		private void Action_PlacePiece()
		{
			CLUBsPiece piece = (CLUBsPiece)ParameterBankStack.Peek()["piece"];
			CLUBsCell cell = (CLUBsCell)ParameterBankStack.Peek()["cell"];

			if (!CLUBsPiece.Icons.ContainsKey((CLUBsString)piece.LocalVariables["Icon"]))
			{
				CLUBsPiece.Icons.Add((CLUBsString)piece.LocalVariables["Icon"], Image.FromFile((CLUBsString)piece.LocalVariables["Icon"]));
			}

			ReturnStack.Pop();

			if (cell == null ||
				(cell.Pieces.Count >= (CLUBsInteger)cell.LocalVariables["MaxPieces"] &&
				(CLUBsInteger)cell.LocalVariables["MaxPieces"] != -1))
			{
				ReturnStack.Push((CLUBsBoolean)false);
				return;
			}

			CLUBsPiece newPiece = new CLUBsPiece();
			newPiece.CopyValueFromObject(piece);

			cell.Pieces.Add(newPiece);
			ReturnStack.Push((CLUBsBoolean)true);

		}

		private void Action_ClearCell()
		{
			CLUBsCell cell = (CLUBsCell)ParameterBankStack.Peek()["cell"];

			cell.Pieces.Clear();
		}

		private void Action_MoveAllPieces()
		{
			CLUBsCell srcCell = (CLUBsCell)ParameterBankStack.Peek()["sourceCell"];
			CLUBsCell tgtCell = (CLUBsCell)ParameterBankStack.Peek()["targetCell"];

			ReturnStack.Pop();

			if (tgtCell.Pieces.Count + srcCell.Pieces.Count > (CLUBsInteger)tgtCell.LocalVariables["MaxPieces"] &&
				(CLUBsInteger)tgtCell.LocalVariables["MaxPieces"] != -1)
			{
				ReturnStack.Push((CLUBsBoolean)false);
				return;
			}

			tgtCell.Pieces.AddRange(srcCell.Pieces);
			srcCell.Pieces.Clear();

			ReturnStack.Push((CLUBsBoolean)true);

		}

		private void Action_ThreeInARow()
		{
			CLUBsBoard board = (CLUBsBoard)ParameterBankStack.Peek()["board"];
			CLUBsPiece piece = (CLUBsPiece)GlobalVariables["CurrentPlayer"].LocalVariables["MainPiece"];//(CLUBsPiece)ParameterBankStack.Peek()["piece"];

			ReturnStack.Pop();

			int width = board.Grid.GetUpperBound(0)+1;
			int height = board.Grid.GetUpperBound(1)+1;

			PieceComparer comp = new PieceComparer();

			for (int x = 0; x < width; x++)
			{
				for (int y = 0; y < height; y++)
				{
					try
					{
						// The piece in the Pieces array is a copy, not the same reference
						if (board.Grid[x, y].Pieces.Contains(piece, comp) &&
							board.Grid[x + 1, y].Pieces.Contains(piece, comp) &&
							board.Grid[x + 2, y].Pieces.Contains(piece, comp))
						{
							ReturnStack.Push((CLUBsBoolean)true);
							return;
						}
					}
					catch (IndexOutOfRangeException)
					{

					}
					try
					{
						if (board.Grid[x, y].Pieces.Contains(piece, comp) &&
							board.Grid[x + 1, y + 1].Pieces.Contains(piece, comp) &&
							board.Grid[x + 2, y + 2].Pieces.Contains(piece, comp))
						{
							ReturnStack.Push((CLUBsBoolean)true);
							return;
						}
					}
					catch (IndexOutOfRangeException)
					{

					} 
					try
					{
						if (board.Grid[x, y].Pieces.Contains(piece, comp) &&
							board.Grid[x - 1, y + 1].Pieces.Contains(piece, comp) &&
							board.Grid[x - 2, y + 2].Pieces.Contains(piece, comp))
						{
							ReturnStack.Push((CLUBsBoolean)true);
							return;
						}
					}
					catch (IndexOutOfRangeException)
					{

					}
					try
					{
						if (board.Grid[x, y].Pieces.Contains(piece, comp) &&
							board.Grid[x, y + 1].Pieces.Contains(piece, comp) &&
							board.Grid[x, y + 2].Pieces.Contains(piece, comp))
						{
							ReturnStack.Push((CLUBsBoolean)true);
							return;
						}
					}
					catch (IndexOutOfRangeException)
					{

					}
				}
			}

			ReturnStack.Push((CLUBsBoolean)false);
		}

		private void Action_FourInARow()
		{
			CLUBsBoard board = (CLUBsBoard)ParameterBankStack.Peek()["board"];
			CLUBsPiece piece = (CLUBsPiece)GlobalVariables["CurrentPlayer"].LocalVariables["MainPiece"];//(CLUBsPiece)ParameterBankStack.Peek()["piece"];

			ReturnStack.Pop();

			int width = board.Grid.GetUpperBound(0) + 1;
			int height = board.Grid.GetUpperBound(1) + 1;

			PieceComparer comp = new PieceComparer();

			for (int x = 0; x < width; x++)
			{
				for (int y = 0; y < height; y++)
				{
					try
					{
						// The piece in the Pieces array is a copy, not the same reference
						if (board.Grid[x, y].Pieces.Contains(piece, comp) &&
							board.Grid[x + 1, y].Pieces.Contains(piece, comp) &&
							board.Grid[x + 2, y].Pieces.Contains(piece, comp) &&
							board.Grid[x + 3, y].Pieces.Contains(piece, comp))
						{
							ReturnStack.Push((CLUBsBoolean)true);
							return;
						}
					}
					catch (IndexOutOfRangeException)
					{

					}
					try
					{
						if (board.Grid[x, y].Pieces.Contains(piece, comp) &&
							board.Grid[x + 1, y + 1].Pieces.Contains(piece, comp) &&
							board.Grid[x + 2, y + 2].Pieces.Contains(piece, comp) &&
							board.Grid[x + 3, y + 3].Pieces.Contains(piece, comp))
						{
							ReturnStack.Push((CLUBsBoolean)true);
							return;
						}
					}
					catch (IndexOutOfRangeException)
					{

					}
					try
					{
						if (board.Grid[x, y].Pieces.Contains(piece, comp) &&
							board.Grid[x - 1, y + 1].Pieces.Contains(piece, comp) &&
							board.Grid[x - 2, y + 2].Pieces.Contains(piece, comp) &&
							board.Grid[x - 3, y + 3].Pieces.Contains(piece, comp))
						{
							ReturnStack.Push((CLUBsBoolean)true);
							return;
						}
					}
					catch (IndexOutOfRangeException)
					{

					}
					try
					{
						if (board.Grid[x, y].Pieces.Contains(piece, comp) &&
							board.Grid[x, y + 1].Pieces.Contains(piece, comp) &&
							board.Grid[x, y + 2].Pieces.Contains(piece, comp) &&
							board.Grid[x, y + 3].Pieces.Contains(piece, comp))
						{
							ReturnStack.Push((CLUBsBoolean)true);
							return;
						}
					}
					catch (IndexOutOfRangeException)
					{

					}
				}
			}

			ReturnStack.Push((CLUBsBoolean)false);
		}

		private void Action_MathAbs()
		{
			CLUBsInteger n = (CLUBsInteger)ParameterBankStack.Peek()["n"];

			ReturnStack.Pop();
			ReturnStack.Push(new CLUBsInteger(Math.Abs(n)));
		}

		private class PieceComparer : IEqualityComparer<CLUBsPiece>
		{
			public bool Equals(CLUBsPiece p1, CLUBsPiece p2)
			{
				return (p1.PrototypeID == p2.PrototypeID);
			}

			public int GetHashCode(CLUBsPiece p)
			{
				return p.PrototypeID;
			}
		}

	}
}
